package com.aiti.ai.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aiti.ai.dto.ai.BoChaWebSearchQueryParamDto;
import com.aiti.ai.dto.ai.BoChaWebSearchResponse;
import com.aiti.ai.dto.ai.SearXNGWebSearchResponse;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * @ description: WebSearchUtils
 * @ auth fcb
 * @ date 2025-03-17 11:43
 **/
@Component
@Slf4j
public class WebSearchUtils {
    @Resource
    private RestTemplate restTemplate;
    private static final String BOCHA_WEB_SEARCH_URL = "https://api.bochaai.com/v1/web-search";
    private static final String SEARXNG_WEB_SEARCH_URL = "http://127.0.0.1:8080/search?q=%s&format=json&engines=%s";

    /**
     * 调用博查API接口进行 网络搜索，将返回结果封装为对象
     * 文档地址：<a href="https://bocha-ai.feishu.cn/wiki/RXEOw02rFiwzGSkd9mUcqoeAnNK">Bocha Web Search API</a>
     * 请求出错时抛出异常，请求正常但返回值不是正常值时，返回null
     * @param paramDto 请求参数
     * @param apiKey 博查apiKey
     * @return {@link BoChaWebSearchResponse}
     */
    public BoChaWebSearchResponse boChaWebSearch(BoChaWebSearchQueryParamDto paramDto, String apiKey) {
        // 1. 校验必填参数
        this.checkBoChaWebSearchParam(paramDto, apiKey);
        // 2. 设置参数默认值
        this.setDefaultValue(paramDto);
        // 3. 构建请求头
        HttpHeaders httpHeaders = this.buildBoChaWebSearchHeader(apiKey);
        log.debug("【博查web search】 请求参数：{}", JSONUtil.toJsonStr(paramDto));
        log.info("【博查web search】 开始请求Bo Cha 接口....");
        HttpEntity<String> requestEntity = new HttpEntity<>(JSONUtil.toJsonStr(paramDto), httpHeaders);
        // 4. 发送请求，判断返回结果
        BoChaWebSearchResponse response = null;
        try {
            ResponseEntity<BoChaWebSearchResponse> responseEntity = restTemplate.exchange(BOCHA_WEB_SEARCH_URL, HttpMethod.POST, requestEntity, BoChaWebSearchResponse.class);
            if(responseEntity.getStatusCode() != HttpStatus.OK) {
                log.error("【博查web search】 请求Bo Cha 接口异常。HttpStatus :{} ", responseEntity.getStatusCode());
                return null;
            } else {
                response = responseEntity.getBody();
                if(response == null) {
                    log.error("【博查web search】 请求Bo Cha 接口异常，响应结果为空");
                    return null;
                }
                log.info("【博查web search】 请求BoCha接口成功，code:{}, logId:{}", response.getCode(), response.getLog_id());
                log.debug("【博查web search】 请求Bo Cha 接口成功，响应结果：{}", JSONUtil.toJsonStr(response));
                if(response.getCode() != 200) {
                    return null;
                }
                log.info("【博查web search】请求Bo Cha 接口正常返回");
                return response;
            }
        }catch (Exception e) {
            log.error("【博查web search】 请求Bo Cha 接口异常，异常信息：{}", ExceptionUtil.stacktraceToString(e));
            throw new RuntimeException("【博查web search】 请求Bo Cha 接口异常，异常信息：" + e.getMessage());
        }
    }

    /**
     * 请求自建的元搜索引擎 searXNG
     * @param query 关键字
     * @return {@link SearXNGWebSearchResponse}
     */
    public SearXNGWebSearchResponse searXNGWebSearchByEngine(String query, String engine) {
        log.info("【查询searXNG】参数：{}", query);
        SearXNGWebSearchResponse response;
        try {
            ResponseEntity<SearXNGWebSearchResponse> responseEntity = restTemplate.getForEntity(String.format(SEARXNG_WEB_SEARCH_URL, query, engine), SearXNGWebSearchResponse.class);
            if(responseEntity.getStatusCode() != HttpStatus.OK) {
                log.error("【查询searXNG】异常。HttpStatus :{} ", responseEntity.getStatusCode());
                return null;
            }
            response = responseEntity.getBody();
            if(response == null) {
                log.error("【查询searXNG】异常，响应结果为空");
                return null;
            }
            return response;
        }catch (Exception e) {
            log.error("【查询searXNG】异常：{}", ExceptionUtil.stacktraceToString(e));
            return null;
        }
    }

    public SearXNGWebSearchResponse searXNGWebSearch(String query) {
        SearXNGWebSearchResponse bing = this.searXNGWebSearchByEngine(query, "bing");
        if(bing == null || CollectionUtil.isEmpty(bing.getResults())) {
            return this.searXNGWebSearchByEngine(query, "baidu");
        }
        return bing;
    }


    /**
     * 使用Jsoup解析网页内容，获取Body内容并去除HTML标签
     * @param url 地址
     * @return String
     */
    public String getWebPageBodyText(String url) {
        try {
            // 1. 获取网页内容
            Document doc = Jsoup.connect(url)
                    .timeout(2000) // 设置超时时间
                    .get();
            // 2. 提取Body内容并去除HTML标签
            return doc.body().text();
        } catch (Exception e) {
            log.error("【使用Jsoup解析网页失败】 url: {}, 异常：{}", url, e.getMessage());
            return "";
        }
    }

    private void checkBoChaWebSearchParam(BoChaWebSearchQueryParamDto paramDto, String apiKey) {
        if(StrUtil.isEmpty(apiKey) || StrUtil.isEmpty(paramDto.getQuery())) {
            throw new IllegalArgumentException("【博查web search】请求参数异常，查询关键字或apiKey不能为空");
        }
    }

    private void setDefaultValue(BoChaWebSearchQueryParamDto paramDto) {
        if(paramDto.getCount() == null) {
            paramDto.setCount(5);
        }
        if(paramDto.getPage() == null) {
            paramDto.setPage(1);
        }
        if(StrUtil.isEmpty(paramDto.getFreshness())) {
            paramDto.setFreshness("noLimit");
        }
    }

    private HttpHeaders buildBoChaWebSearchHeader(String apiKey) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", apiKey);
        headers.add("Content-Type", "application/json");
        return headers;
    }
}
